#include "CSession.h"
#include"CServer.h"//头文件声明了CSErver,这里也要包含一下
#include"LogicSystem.h"
CSession::CSession(boost::asio::io_context& io_context, CServer* server) :_io_context(io_context),
_server(server) ,_socket(io_context),_b_close(false){
	boost::uuids::uuid a_uuid=boost::uuids::random_generator()();
	_uuid = boost::uuids::to_string(a_uuid);
	_recv_head_node = make_shared<MsgNode>(HEAD_TOTAL_LEN);
}
tcp::socket& CSession::GetSocket() {
	return _socket;
}
std::string& CSession::GetUuid() {
	return _uuid;
}
void CSession::Start() {
	auto shared_this = shared_from_this();//用这种方式让自己的智能指针计数加一
	//开启协程,接收
	//这里以值形式捕获了局部变量,引用计数也加一
	//-> b表示lambda函数返回一个什么类型<实际返回类型>
	boost::asio::co_spawn(_io_context, [=]()->boost::asio::awaitable<void> {
		try {
			for (; !_b_close;) {
				_recv_head_node->Clear();
				size_t n = co_await boost::asio::async_read(_socket, boost::asio::buffer(_recv_head_node->_data, HEAD_TOTAL_LEN), use_awaitable);
				if (n == 0) {
					std::cout << "receive peer closed" << endl;
					Close();
					_server->ClearSession(_uuid);
					co_return;
				}
				//获取头部MSGID数据
				short msg_id = 0;
				memcpy(&msg_id, _recv_head_node->_data, HEAD_ID_LEN);
				msg_id = boost::asio::detail::socket_ops::network_to_host_short(msg_id);
				cout << "msg_id is:" << msg_id << endl;
				if (msg_id > MAX_LENGTH) {
					std::cout << "incalid msg id is:" << msg_id << endl;
					Close();
					_server->ClearSession(_uuid);
					co_return;
				}
				//解析长度
				short msg_len = 0;
				memcpy(&msg_len, _recv_head_node->_data + HEAD_ID_LEN, HEAD_DATA_LEN);
				msg_len = boost::asio::detail::socket_ops::network_to_host_short(msg_len);
				if (msg_len > MAX_LENGTH) {
					std::cout << "incalid msg len is:" << msg_id << endl;
					Close();
					_server->ClearSession(_uuid);
					co_return;
				}

				_recv_msg_node = make_shared<RecvNode>(msg_len, msg_id);
				//读出包体
				n == co_await boost::asio::async_read(_socket, boost::asio::buffer(_recv_msg_node->_data, _recv_msg_node->_total_len), use_awaitable);
				if (n == 0) {
					std::cout << "receive peer closed" << endl;
					Close();
					_server->ClearSession(_uuid);
					co_return;
				}
				_recv_msg_node->_data[_recv_msg_node->_total_len] = '\0';
				cout << "receive data is: " << _recv_msg_node->_data << endl;
				//收到数据后投递给逻辑线程处理
				LogicSystem::GetInstance().PostMsgToQue(make_shared<LogicNode>(shared_from_this(), _recv_msg_node));
			}
		}
		catch (std::exception& e) {
			std::cerr << "exception is :" << e.what() << endl;
			Close();
			_server->ClearSession(_uuid);
		}
		}, boost::asio::detached);
}
void CSession::Close(){
	_socket.close();
	_b_close = true;
}
CSession::~CSession() {
	try {
		std::cout << "~CSession destruct" << endl;
		Close();
	}
	catch (exception& e) {
		cout << "exception is " << e.what() << endl;
	}
}
//为什么发送不用协程?发送实在逻辑线程,我们不想给逻辑线程带来太多开销
void CSession::Send(const char* msg, short max_length, short msgid) {
	std::unique_lock<std::mutex> lock(_send_lock);
	int send_que_size = _send_que.size();
	if (send_que_size > MAX_SENDQUE) {
		std::cout << "session:" << _uuid << "send que fulled,size is " << MAX_SENDQUE << endl;
		return;
	}
	_send_que.push(make_shared<SendNode>(msg, max_length, msgid));
	if (send_que_size > 0)//push前没有数据就发送,有数据就退出
		return;
	auto msgnode = _send_que.front();
	lock.unlock();//数据取出来就解锁了,尽量不要多占用锁,提升并发性;
	boost::asio::async_write(_socket, boost::asio::buffer(msgnode->_data, msgnode->_total_len), 
		std::bind(&CSession::HandleWrite, this, std::placeholders::_1,SharedSelf()));
}
std::shared_ptr<CSession>CSession::SharedSelf() {
	return shared_from_this();
}
void CSession::Send(std::string msg, short msgid) {
	Send(msg.c_str(), msg.length(), msgid);

}
void CSession::HandleWrite(const boost::system::error_code& error, std::shared_ptr<CSession> shared_self) {
	try {
		if (!error) {
			std::unique_lock<std::mutex> lock(_send_lock);
			_send_que.pop();//写完了会调用回调函数,所以在这里出队
			if (!_send_que.empty()) {
				auto msgnode = _send_que.front();
				lock.unlock();
				boost::asio::async_write(_socket, boost::asio::buffer(msgnode->_data, msgnode->_total_len),
					std::bind(&CSession::HandleWrite, this, std::placeholders::_1, shared_self));
			}
			else {
				cout << "handlewrite failed,error is " << error.what() << endl;
				Close();
				_server->ClearSession(_uuid);
			}
		}
	}
	catch(std::exception& e) {
		cout << "exception is:" << e.what() << endl;
		Close();
		_server->ClearSession(_uuid);
	}
}
LogicNode::LogicNode(shared_ptr<CSession> session, shared_ptr<RecvNode> recvnode) :_session(session), _recvnode(recvnode) {

}